# 5. docker之容器数据存储,数据挂载

# 数据挂载分类

docker提供三种方式将数据从宿主机挂载到容器中:

  1. volumes(存储之卷/数据卷):Docker管理宿主机文件系统的一部分。保存数据的最佳方式。(存储路径:/var/lib/docker/volumes)
  2. bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
  3. tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用 tmpfs,同时避免写入容器可写层提高性能

GxhldI.png

# volume模式

# volume数据卷

volumes(存储之卷/数据卷):Docker管理宿主机文件系统的一部分。保存数据的最佳方式。(存储路径:/var/lib/docker/volumes)

Docker中的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中称为数据卷(Data Volume)。数据卷可以用来存储Docker应用的数据,也可以用来在Docker容器间进行数据共享。

数据卷呈现给Docker容器的形式就是一个目录,支持多个容器间共享,修改也不会影响镜像。使用Docker的数据卷,类似在系统中使用 mount 挂载一个文件系统。

  1. 一个数据卷是一个特别指定的目录,该目录利用容器的UFS文件系统可以为容器提供一些稳定的特性或者数据共享。数据卷可以在多个容器之间共享。

  2. 创建数据卷,只要在docker run命令后面跟上-v或--mount参数即可创建一个数据卷,当然也可以跟多个-v或--mount参数来创建多个数据卷,当创建好带有数据卷的容器后, 就可以在其他容器中通过--volumes-froms参数来挂载该数据卷了,而不管该容器是否运行。也可以在Dockerfile中通过VOLUME指令来增加一个或者多个数据卷。

  3. 如果有一些数据想在多个容器间共享,或者想在一些临时性的容器中使用该数据,那么最好的方案就是你创建一个数据卷容器,然后从该临时性的容器中挂载该数据卷容器的数据。 这样,即使删除了刚开始的第一个数据卷容器或者中间层的数据卷容器,只要有其他容器使用数据卷,数据卷都不会被删除的。

  4. 不能使用docker export、save、cp等命令来备份数据卷的内容,因为数据卷是存在于镜像之外的。备份的方法可以是创建一个新容器,挂载数据卷容器,同时挂载一个本地目录, 然后把远程数据卷容器的数据卷通过备份命令备份到映射的本地目录里面。

    ##例如
    docker run -rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
    
  5. 也可以把一个本地主机的目录当做数据卷挂载在容器上,同样是在docker run后面跟-v或--mount参数,不过-v或或--mount后面跟的不再是单独的目录了,它是

    [host-dir]:[container-dir]:[rw|ro]
    

    这样格式的, host-dir是一个绝对路径的地址,如果host-dir不存在,则docker会创建一个新的数据卷,如果host-dir存在,但是指向的是一个不存在的目录,则docker也会创建该目录,然后使用该目录做数据源。

Docker Volume数据卷可以实现:

  1. 绕过“拷贝写”系统,以达到本地磁盘IO的性能,(比如运行一个容器,在容器中对数据卷修改内容,会直接改变宿主机上的数据卷中的内容,所以是本地磁盘IO的性能,而不是先在容器中写一份,最后还要将容器中的修改的内容拷贝出来进行同步。)
  2. 绕过“拷贝写”系统,有些文件不需要在docker commit打包进镜像文件。
  3. 数据卷可以在容器间共享和重用数据
  4. 数据卷可以在宿主和容器间共享数据
  5. 数据卷数据改变是直接修改的
  6. 数据卷是持续性的,直到没有容器使用它们。即便是初始的数据卷容器或中间层的数据卷容器删除了,只要还有其他的容器使用数据卷,那么里面的数据都不会丢失

注意:数据卷容器,拉取一台centos的镜像,挂载上数据卷,这台容器的功能就只有一个,

# volume命令

# 创建数据卷 - create

docker volume create 卷名

# 查看数据卷列表 - ls

docker volume ls

# 查看一个数据卷的详细信息 - inspect

docker volume inspect 卷名

# 删除指定的数据卷 - rm

docker volume rm 卷名

# 创建容器时,挂载数据卷

docker container run -itd --mount src=nginx,dst=/usr/share/nginx/html/ nginx

## src=数据卷名,dst=容器挂载点路径
## 如果数据卷不存在,默认会自动创建

# bind mount模式

bind mounts:将宿主机上的任意位置的文件或者目录挂载到容器中

在docker的早期版本中就存在的功能,与volumes相比,他的功能比较局限。当使用bind mounts时,宿主机的目录或文件被挂载到容器中。容器将按照挂载目录或文件的绝对路径来使用或修改宿主机的中的数据。宿主机中的目录或文件不需要预先存在,在需要的时候会自动创建。

使用Bind mounts在性能上是非常好的,但这依赖于宿主机有一个目录妥善结构化的文件系统。如果你要创建一个新的Docker应用,我们仍推荐使用named volume的方式,因为你无法通过Docker CLI来管理bind mounts。

警告:bind mounts是一把双刃剑,因为使用bind mounts的容器可以在通过容器内部的进程对主机文件系统进行修改,包括创建,修改和删除重要的系统文件和目录,这个功能虽然很强大,但显然也会造成安全方面的影响,包括影响到宿主机上Docker以外的进程

# bind mount模式注意事项

  1. bind mount 没有管理命令
  2. bind挂载,是从宿主机挂载到容器中的,如果容器中的挂载点有数据,那么这些数据会隐藏,直到取消挂载

# 创建容器挂载宿主机中指定目录到容器中

docker container run -d -p81:80 --mount type=bind,src=/root/1/,dst=/usr/share/nginx/html nginx


## type=挂载类型,src=宿主机的挂载原目录,dst=容器挂载点路径
## 你访问一下本地IP加81端口,就会返回403页面,因为没有index.html文件,可以在宿主机上的挂载原目录中添加index.html文件并写上一些话,在访问就正常了

# 二个持久化模式特点

# volume特点

  1. 多个运行容器之间共享数据,多个容器可以同时挂载相同的卷
  2. 当容器停止或被移除时,该卷依然存在
  3. 当明确删除卷时,卷才会被删除
  4. 将容器的数据存储到远程主机或其他存储上(挂载一个文件服务器到docker的数据目录,这样所有的数据就存储在了远程上)
  5. 将数据从一台docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/valumes/)

# bind mount特点

  1. 从主机共享配置文件到容器,默认情况下,挂载主机/etc/resolv.conf到每个容器,提供dns解析
  2. 在docker主机上的开发环境和容器之间共享源代码
    1. 例如:可以将maven target目录挂载到容器中,每次docker主机上构建maven项目时,容器都可以访问构建的项目包
  3. 当docker主机的文件或目录结构保证与容器所需的绑定挂载一致